import pytest
import responses
import json
from copy import deepcopy
import requests

# 腾讯云API密钥（请仅在测试环境使用，生产环境请勿硬编码密钥）
SECRET_ID = "AKIDoTvAC0c4SkvuGeu20mX9bqulaLyPfpqj"
SECRET_KEY = "kLjx2sVvDJCvWxCHAtSSN8g3GMI2kJk1"

# 测试数据配置（严格遵循官方文档格式）
TEST_INSTANCE_IDS = ["ins-2zvpghhc"]  # 官方示例值，需替换为真实存在的实例ID列表
DEFAULT_PARAMS = {
    "Action": "ModifyInstanceSpec",
    "InstanceIds.0": TEST_INSTANCE_IDS[0],  # 必须是数组第一个元素
    "InstanceType": "S5.LARGE8",  # 示例值：需替换为实际支持的规格
    "CpuId": 8,  # 示例值：需替换为实际支持的CPU核数
    "Memory": 16  # 示例值：需替换为实际支持的内存大小（GB）
}

# 完整错误码映射表（根据实际文档补充）
ERROR_CODE_MAP = {
    # 参数缺失类
    "MissingParameter.InstanceIds": "缺少必填参数InstanceIds",
    "MissingParameter.InstanceType": "缺少必填参数InstanceType",
    "MissingParameter.CpuId": "缺少必填参数CpuId",
    "MissingParameter.Memory": "缺少必填参数Memory",

    # 参数无效类
    "InvalidParameterValue.InstanceType": "实例类型无效",
    "InvalidParameterValue.CpuId": "CPU核数无效",
    "InvalidParameterValue.Memory": "内存大小无效",
    "InvalidParameterValue.InstanceIds": "实例ID列表无效",

    # 资源状态类
    "ResourceInUse.Instance": "实例正在使用中",
    "ResourceUnavailable.Instance": "实例不可用",
    "InstanceNotFound": "实例不存在",

    # 权限类
    "UnauthorizedOperation": "权限不足",
    "UnauthorizedOperation.Instance": "无实例操作权限",

    # 内部错误类
    "InternalError": "内部服务错误",
    "InternalServerError": "服务器内部错误",
    "UnknownParameter": "未知参数",
    "InvalidParameterCombination": "参数组合错误"
}


# 模拟认证头生成函数
def generate_auth_headers(secret_id, secret_key):
    """生成符合腾讯云规范的签名头"""
    return {
        "Authorization": f"TC3-HMAC-SHA256 Credential={secret_id}/{secret_key}",
        "Content-Type": "application/json",
        "X-TC-Action": "ModifyInstanceSpec",
        "X-TC-Version": "2017-03-12",
        "X-TC-Timestamp": "1710230358",
        "X-TC-Nonce": "123456789"
    }


# 测试基类
class TestModifyInstanceSpec:

    @pytest.fixture(scope="session")
    def auth_headers(self):
        """认证头生成 fixture"""
        return generate_auth_headers(SECRET_ID, SECRET_KEY)

    # 正常用例
    @responses.activate
    def test_success_case(self, auth_headers):
        """正常调整实例配置询价"""
        expected_response = {"Response": {"RequestId": "req-12345678"}}
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=expected_response, status=200)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(DEFAULT_PARAMS)
        )
        assert response.status_code == 200
        assert "RequestId" in response.json()["Response"]

    # 参数缺失测试（4个必填参数）
    @pytest.mark.parametrize("missing_param", [
        "InstanceIds.0",  # 实例ID列表缺失
        "InstanceType",  # 实例类型缺失
        "CpuId",  # CPU核数缺失
        "Memory"  # 内存大小缺失
    ])
    @responses.activate
    def test_missing_required_params(self, missing_param, auth_headers):
        """测试必填参数缺失场景"""
        params = deepcopy(DEFAULT_PARAMS)
        del params[missing_param]

        error_response = {
            "Response": {
                "Error": {
                    "Code": f"MissingParameter.{missing_param}",
                    "Message": ERROR_CODE_MAP[f"MissingParameter.{missing_param}"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=400)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(params)
        )

        assert response.status_code == 400
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]

    # 参数无效测试（6个无效值场景）
    @pytest.mark.parametrize("invalid_instance_type", [
        "S1.SMALL1",  # 不支持规格
        "INVALID_TYPE",  # 非法值
        ""  # 空字符串
    ])
    @responses.activate
    def test_invalid_instance_type(self, invalid_instance_type, auth_headers):
        """测试无效实例类型场景"""
        params = deepcopy(DEFAULT_PARAMS)
        params["InstanceType"] = invalid_instance_type

        error_response = {
            "Response": {
                "Error": {
                    "Code": "InvalidParameterValue.InstanceType",
                    "Message": ERROR_CODE_MAP["InvalidParameterValue.InstanceType"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=400)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(params)
        )

        assert response.status_code == 400
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]

    @pytest.mark.parametrize("invalid_cpu_id", [
        0,  # 非法数值
        100,  # 超出范围
        "EIGHT"  # 非数字格式
    ])
    @responses.activate
    def test_invalid_cpu_id(self, invalid_cpu_id, auth_headers):
        """测试无效CPU核数场景"""
        params = deepcopy(DEFAULT_PARAMS)
        params["CpuId"] = invalid_cpu_id

        error_response = {
            "Response": {
                "Error": {
                    "Code": "InvalidParameterValue.CpuId",
                    "Message": ERROR_CODE_MAP["InvalidParameterValue.CpuId"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=400)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(params)
        )

        assert response.status_code == 400
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]

    @pytest.mark.parametrize("invalid_memory", [
        0,  # 非法数值
        1024,  # 超出范围
        "SIXTEEN_GB"  # 非数字格式
    ])
    @responses.activate
    def test_invalid_memory(self, invalid_memory, auth_headers):
        """测试无效内存大小场景"""
        params = deepcopy(DEFAULT_PARAMS)
        params["Memory"] = invalid_memory

        error_response = {
            "Response": {
                "Error": {
                    "Code": "InvalidParameterValue.Memory",
                    "Message": ERROR_CODE_MAP["InvalidParameterValue.Memory"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=400)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(params)
        )

        assert response.status_code == 400
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]

    # 资源状态测试（3个场景）
    @responses.activate
    def test_instance_not_found(self, auth_headers):
        """测试实例不存在场景"""
        params = deepcopy(DEFAULT_PARAMS)
        params["InstanceIds.0"] = "ins-invalid-123"

        error_response = {
            "Response": {
                "Error": {
                    "Code": "InstanceNotFound",
                    "Message": ERROR_CODE_MAP["InstanceNotFound"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=404)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(params)
        )

        assert response.status_code == 404
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]

    @responses.activate
    def test_resource_in_use(self, auth_headers):
        """测试实例正在使用中场景"""
        error_response = {
            "Response": {
                "Error": {
                    "Code": "ResourceInUse.Instance",
                    "Message": ERROR_CODE_MAP["ResourceInUse.Instance"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=400)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(DEFAULT_PARAMS)
        )

        assert response.status_code == 400
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]

    @responses.activate
    def test_unauthorized_operation(self, auth_headers):
        """测试权限不足场景"""
        error_response = {
            "Response": {
                "Error": {
                    "Code": "UnauthorizedOperation",
                    "Message": ERROR_CODE_MAP["UnauthorizedOperation"]
                }
            }
        }
        responses.add(responses.POST, "https://cvm.tencentcloudapi.com/",
                      json=error_response, status=403)

        response = requests.post(
            "https://cvm.tencentcloudapi.com/",
            headers=auth_headers,
            data=json.dumps(DEFAULT_PARAMS)
        )

        assert response.status_code == 403
        assert error_response["Response"]["Error"]["Code"] == response.json()["Response"]["Error"]["Code"]


# 执行测试
if __name__ == "__main__":
    pytest.main([
        __file__,
        "-v",
        "--alluredir=./allure-results",
        "--html=./report.html"
    ])